package com.sweetcircle.utils;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * &#064;project_name: sweet-circle-server
 * &#064;Author: Anan
 * &#064;time: 2024/8/9 下午9:11
 */


public class QRCodeUtils {


    /**
     * 按照自定义内容、宽度、高度、纠错等级、字符集、编剧创建QR码比特矩阵。
     *
     * @param content 二维码内容
     * @param width 二维码宽度
     * @param height 二维码高度
     * @param errCorrLevel 纠错等级，可以是<code>L, M, Q, H</code>
     * @param charSet 字符集
     * @param margin 边距
     * @return BitMatrix 二维码比特矩阵
     * @throws WriterException
     */
    public static BitMatrix createQRCodeBitMatrix(String content, int width, int height,
                                                  ErrorCorrectionLevel errCorrLevel,
                                                  String charSet, int margin) throws WriterException {
        if (width <= 0) {
            width = 100;
        }
        if (height <= 0) {
            height = 100;
        }
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, errCorrLevel); // 设置纠错等级
        hints.put(EncodeHintType.CHARACTER_SET, charSet); // 设置编码方式
        hints.put(EncodeHintType.MARGIN, margin); // 设置边距
        return new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
    }

    /**
     * 创建二维码，返回字节数组
     *
     * @param content 二维码内容
     * @param width 宽度
     * @param height 高度
     * @return byte[]
     * @throws WriterException
     * @throws IOException
     */
    public static byte[] createQRCode(String content, int width, int height)
            throws WriterException, IOException {
        BitMatrix bitMatrix = createQRCodeBitMatrix(content, width, height, ErrorCorrectionLevel.H, "UTF-8", 1);

        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage, "png", baos);
            baos.flush();
            byte[] byteArray = baos.toByteArray();
            baos.close();
            return byteArray;
        } catch (Exception e) {
            throw new RuntimeException("将 BufferedImage 转换为字节数组时出错。", e);
        }

    }

    /**
     * 创建二维码，返回base64字节流
     *
     * @param content 二维码里的内容
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return byte[] base64字节数组
     */
    public static byte[] createQRCodeBase64Bytes(String content ,int width , int height)
            throws WriterException, IOException {
        byte[] bytes = createQRCode(content , width, height);
        return Base64.getEncoder().encode(bytes);
    }

    /**
     * 创建二维码，返回base64字符串
     *
     * @param content 二维码里的内容
     * @param imageFormat 图片后缀名
     * @param width 二维码宽度
     * @param height 二维码高度
     * @return String base64字符串
     */
    public static String createQRCodeBase64(String content , String imageFormat , int width , int height,
                                            String encoding) throws WriterException, IOException {
        return new String(createQRCodeBase64Bytes(content, width, height), encoding);
    }

    /**
     * 转换为BufferedImage
     *
     * @param bitMatrix 比特矩阵
     * @param onColor 条码颜色
     * @param offColor 背景颜色
     * @return java.awt.image.BufferedImage
     */
    public static BufferedImage toBufferedImage(BitMatrix bitMatrix, int onColor, int offColor) {
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(onColor, offColor);
        return MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
    }


    /**
     * 转换为BufferedImage
     * @return java.awt.image.BufferedImage
     */
    public static BufferedImage createQRCodeBufferedImage(String content ,int width , int height) throws WriterException {
        BitMatrix bitMatrix = createQRCodeBitMatrix(content, width, height, ErrorCorrectionLevel.H, "UTF-8", 1);
        MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig();
        return MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
    }

    public static byte[] createQRCodeLog(String content ,int width , int height,String logPath) throws WriterException {
        BitMatrix qrCodeBitMatrix = createQRCodeBitMatrix(content, width, height, ErrorCorrectionLevel.H, "UTF-8", 1);

        int width2 = qrCodeBitMatrix.getWidth();
        int height2 = qrCodeBitMatrix.getHeight();
        BufferedImage qrImg = new BufferedImage(width2, height2, BufferedImage.TYPE_3BYTE_BGR);
        for (int x = 0; x < width2; x++) {
            for (int y = 0; y < height2; y++) {
                qrImg.setRGB(x, y, qrCodeBitMatrix.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
            }
        }
        Graphics2D graphics = qrImg.createGraphics();
        try {
            BufferedImage logImage = ImageIO.read(new File(logPath));
            int widthAndHeight = qrImg.getWidth() < qrImg.getHeight() ?
                    qrImg.getWidth() / 5 :
                    qrImg.getHeight() / 5;
            int x = (qrImg.getWidth() - widthAndHeight) / 2;
            int y = (qrImg.getHeight() - widthAndHeight) / 2;
            graphics.drawImage(logImage, x, y, widthAndHeight, widthAndHeight, null);
            logImage.flush();
            graphics.dispose();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        try {
            ImageIO.write(qrImg, "png", bytes);
            return bytes.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String parseQRCode(byte[] data) throws NotFoundException, IOException {
        if (data.length == 0) return "";
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
        BufferedImage image = ImageIO.read(byteArrayInputStream);
        BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        Result result = new MultiFormatReader().decode(bitmap);
        return result.getText();
    }

    public static BufferedImage convertBytesToBufferedImage(byte[] data) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
        try {
           return ImageIO.read(byteArrayInputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}
